use quote::quote;
use syn::{Ident, Type};
mod utils;

/// 表信息结构体
pub struct TableInfo {
    pub table_name: String,       // 表名称
    pub struct_name: Ident,       // 类名称
    pub primary_key: Vec<String>, // 主键
    pub columns: Vec<ColumnInfo>, // 字段
}

/// 字段信息结构体
pub struct ColumnInfo {
    pub column_name: String,      // 字段名称
    pub data_type: Type,          // 字段数据类型
    pub data_ident: Ident,        // 字段名Struct
    pub database_type: String,    // 字段类型
    pub length: String,           // 字段长度
    pub nullable: String,         // 字段是否为空
    pub comment: String,          // 字段备注
    pub key: String,              // 字段键类型 空：普通键，primary：主键，foreign：外键（未实现）
    pub index: String,            // 字段索引类型  空：无索引，unique：唯一索引，key：普通索引
}

/// 将 `DeriveInput` 转换为 `TableInfo`
pub fn get_table_info(ast: &syn::DeriveInput) -> TableInfo {
    // 解析字段
    let columns = if let syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(syn::FieldsNamed { ref named, .. }), .. }) = ast.data {
        named.iter().filter_map(|field| {
            let ident = field.ident.as_ref()?;
            let column_name = ident.to_string();
            let data_ident = ident.clone();
            let data_type = field.ty.clone();
            let db_type = utils::rust_type_to_dbtype(&data_type);

            let length = utils::get_column_attribute_value(&field.attrs, "length");
            let nullable = utils::get_column_attribute_value(&field.attrs, "nullable");
            let comment = utils::get_column_attribute_value(&field.attrs, "comment");
            let key = utils::get_column_attribute_value(&field.attrs, "key");
            let index = utils::get_column_attribute_value(&field.attrs, "index");

            Some(ColumnInfo {
                column_name,
                data_type,
                data_ident,
                database_type: db_type,
                length,
                nullable,
                comment,
                key,
                index,
            })
        }).collect()
    } else {
        Vec::new()
    };

    // 解析表
    let primary_key = utils::get_attribute_value(&ast, "primary_key")
        .split(',')
        .filter(|s| !s.is_empty())
        .map(|s| s.to_string())
        .collect();

    let table_name = utils::get_table_name(&ast);
    let struct_name = ast.ident.clone();

    TableInfo {
        table_name,
        primary_key,
        struct_name,
        columns,
    }
}

/// 生成建表函数
pub fn impl_create(table_info: &TableInfo) -> syn::__private::TokenStream2 {
    let table_name = &table_info.table_name;
    // 字段设置
    let mut settings = Vec::new();
    for column in &table_info.columns {
        let mut s = format!("`{}` {}", column.column_name, column.database_type);
        if column.length != "" && column.database_type != "bool" && column.database_type != "float" && column.database_type != "double" {
            s.push_str(&format!("({})", column.length));
        }
        if column.nullable == "false" {
            s.push_str(" not null");
        }
        s.push_str(&format!(" comment '{}'", column.comment));
        settings.push(s);
    }
    // 主键设置
    if table_info.primary_key.len() > 0 {
        settings.push(format!("primary key ({})", table_info.primary_key.join(",")));
    }
    // 索引设置
    for column in &table_info.columns {
        if column.index == "key" || column.index == "unique" || column.index == "index" {
            settings.push(format!("{} `{}` (`{}`)", column.index, column.column_name, column.column_name));
        }
    }
    // 合并字段设置
    let columns_setting = settings.join(",\n");
    quote! {
        pub fn create() {
            let ctx = &mut sim_context::get_sim_context();
            let ctx_sql = ctx.get_sql_sim_context();
            let sql = format!("create table `{}` (\n{}\n);", #table_name, #columns_setting);
            ctx_sql.execute_ddl(&sql);
            sim_context::log("create_table");
        }
    }
}

/// 生成插入函数
pub fn impl_insert(table_info: &TableInfo) -> syn::__private::TokenStream2 {
    let struct_name = &table_info.struct_name;
    let table_name = &table_info.table_name;
    let mut fields = Vec::new();
    let mut struct_to_values = Vec::new();
    for idx in 0..table_info.columns.len() {
        // 字段名
        let column_name = &table_info.columns[idx].column_name;
        fields.push((&column_name).clone());
        // easycode 转 struct 的quote
        let data_ident = &table_info.columns[idx].data_ident;
        struct_to_values.push(
            quote! {
                values.push(format!("{}", data.#data_ident));
            }
        );
    }
    let fields_str = fields.iter().map(|s| s.to_string()).collect::<Vec<String>>().join("`,`");
    quote! {
        pub fn insert(data: &#struct_name) -> Result<i32, result_code> {
            let ctx = &mut sim_context::get_sim_context();
            let ctx_sql = ctx.get_sql_sim_context();
            let values = Self::struct_to_values(data);
            let sql = format!("INSERT INTO `{}`(`{}`) VALUES {};", #table_name, #fields_str, values);
            let r = ctx_sql.execute_update(&sql);
            r
        }

        pub fn insert_all(datas: Vec<&#struct_name>) -> Result<i32, result_code> {
            let ctx = &mut sim_context::get_sim_context();
            let ctx_sql = ctx.get_sql_sim_context();
            let mut values = Vec::new();
            for data in datas {
                values.push(Self::struct_to_values(data));
            }
            let sql = format!("INSERT INTO `{}`(`{}`) VALUES {};", #table_name, #fields_str, values.join(","));
            let r = ctx_sql.execute_update(&sql);
            r
        }

        pub fn struct_to_values(data: &#struct_name) -> String {
            let mut values = Vec::new();
            #(#struct_to_values)*
            format!("('{}')", values.join("','"))
        }
    }
}

/// 生成查询函数
pub fn impl_query(table_info: &TableInfo) -> syn::__private::TokenStream2 {
    let struct_name = &table_info.struct_name;
    let table_name = &table_info.table_name;
    let mut fields = Vec::new();
    let mut column_names = Vec::new();
    let mut data_idents = Vec::new();
    let mut types = Vec::new();

    for column in &table_info.columns {
        fields.push((&column.column_name).clone());
        column_names.push(&column.column_name);
        data_idents.push(&column.data_ident);
        types.push(&column.data_type);
    }

    let fields_str = fields.iter().map(|s| s.to_string()).collect::<Vec<String>>().join("`,`");
    
    // 获取第一个主键字段或第一个普通字段
    let first_field = if !table_info.primary_key.is_empty() {
        &table_info.primary_key[0]
    } else {
        &table_info.columns[0].column_name
    };
    
    quote! {
        pub fn query(conditions: &[Condition], fields: Option<Vec<&str>>) -> Option<Vec<#struct_name>> {
            let mut params = Vec::new();
            for condition in conditions {
                params.push(condition.to_sql());
            }
            let select_fields = match fields {
                Some(f) => format!("`{}`", f.join("`,`")),
                None => format!("`{}`", #fields_str)
            };
            Self::query_by_sql(format!("SELECT {} FROM `{}` WHERE {};", select_fields, #table_name, params.join(" AND ")))
        }

        pub fn query_page(conditions: &[Condition], page: i32, page_size: i32, fields: Option<Vec<&str>>) -> Option<(Vec<#struct_name>, i64)> {
            let mut params = Vec::new();
            for condition in conditions {
                params.push(condition.to_sql());
            }
            let where_clause = if params.is_empty() {
                "1=1".to_string()
            } else {
                params.join(" AND ")
            };
            
            let count_sql = format!("SELECT COUNT(*) as total FROM `{}` WHERE {};", #table_name, where_clause);
            let ctx = &mut sim_context::get_sim_context();
            let ctx_sql = ctx.get_sql_sim_context();
            let count_result = ctx_sql.execute_query(&count_sql);
            let total = match count_result {
                Ok(rows) => {
                    if rows.has_next() {
                        let row = rows.next_row().unwrap();
                        match row.get_bytes_as_utf8_string("total") {
                            Ok(val) => val.parse::<i64>().unwrap_or(0),
                            Err(_) => 0
                        }
                    } else {
                        0
                    }
                },
                Err(_) => return None,
            };

            let offset = (page - 1) * page_size;
            let select_fields = match fields {
                Some(f) => format!("`{}`", f.join("`,`")),
                None => format!("`{}`", #fields_str)
            };
            let query_sql = format!(
                "SELECT {} FROM `{}` WHERE {} LIMIT {} OFFSET {};",
                select_fields, #table_name, where_clause, page_size, offset
            );
            
            match Self::query_by_sql(query_sql) {
                Some(data) => Some((data, total)),
                None => None,
            }
        }

        pub fn exist(conditions: &[Condition]) -> bool {
            let mut params = Vec::new();
            for condition in conditions {
                params.push(condition.to_sql());
            }
            
            let ctx = &mut sim_context::get_sim_context();
            let ctx_sql = ctx.get_sql_sim_context();
            let sql = format!(
                "SELECT `{}` FROM `{}` WHERE {} LIMIT 1;",
                #first_field,
                #table_name,
                params.join(" AND ")
            );
            
            match ctx_sql.execute_query(&sql) {
                Ok(rows) => rows.has_next(),
                Err(_) => false
            }
        }

        pub fn query_by_sql(sql: String) -> Option<Vec<#struct_name>> {
            let ctx = &mut sim_context::get_sim_context();
            let ctx_sql = ctx.get_sql_sim_context();
            let r = ctx_sql.execute_query(&sql);
            match r {
                Ok(rows) => {
                    let mut result: Vec<#struct_name> = Vec::new();
                    while rows.has_next() {
                        let ac_ec = rows.next_row().unwrap();
                        result.push(#struct_name {
                            #(
                                #data_idents: {
                                    let val = ac_ec.get_bytes_as_utf8_string(#column_names);
                                    match val {
                                        Ok(v) => v.parse::<#types>().unwrap_or_default(),
                                        Err(_) => Default::default()
                                    }
                                }
                            ),*
                        });
                    }
                    Some(result)
                },
                Err(e) => {
                    ctx.error(&format!("ErrorCode:{}", e));
                    None
                },
            }
        }
    }
}

/// 生成删除函数
pub fn impl_delete(table_info: &TableInfo) -> syn::__private::TokenStream2 {
    let table_name = &table_info.table_name;
    quote! {
        pub fn delete(conditions: &[Condition]) -> Result<i32, result_code> {
            let mut params = Vec::new();
            for condition in conditions {
                params.push(condition.to_sql());
            }
            let ctx = &mut sim_context::get_sim_context();
            let ctx_sql = ctx.get_sql_sim_context();
            let sql = format!("DELETE FROM `{}` WHERE {};", #table_name, params.join(" AND "));
            let r = ctx_sql.execute_update(&sql);
            r
        }
    }
}

/// 生成更新函数
pub fn impl_update(table_info: &TableInfo) -> syn::__private::TokenStream2 {
    let table_name = &table_info.table_name;
    let struct_name = &table_info.struct_name;
    let mut set_clauses = Vec::new();
    let mut where_clauses = Vec::new();
    for column in &table_info.columns {
        let column_name = &column.column_name;
        let data_ident = &column.data_ident;
        if table_info.primary_key.contains(&column_name) {
            where_clauses.push(quote! {
                format!("`{}`='{}'", #column_name, data.#data_ident)
            });
        } else {
            set_clauses.push(quote! {
                format!("`{}`='{}'", #column_name, data.#data_ident)
            });
        }
    }
    
    let set_clause = quote! {
        vec![#(#set_clauses),*].iter().map(|s| s.to_string()).collect::<Vec<String>>().join(", ")
    };

    let where_clause = quote! {
        vec![#(#where_clauses),*].iter().map(|s| s.to_string()).collect::<Vec<String>>().join(" AND ")
    };

    quote! {
        pub fn update(data: &#struct_name) -> Result<i32, result_code> {
            let ctx = &mut sim_context::get_sim_context();
            let ctx_sql = ctx.get_sql_sim_context();
            let sql = format!(
                "UPDATE `{}` SET {} WHERE {};",
                #table_name,
                #set_clause,
                #where_clause
            );
            let r = ctx_sql.execute_update(&sql);
            r
        }
    }
}